from fastapi import HTTPException, status
from datetime import datetime, timedelta
import jwt
import re
import random
from ..repositories import users_repository
from ..utils.password_utils import encrypt_password, decrypt_password


class AuthService:
    __SECRET_KEY = "key"
    __ALGORITHM = "HS256"
    __ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24

    def __init__(self):
        self.users_repository = users_repository

    async def verify_code(self, phone):
        """
        生成并存储验证码
        :param phone: 手机号
        :return: (bool, str) - (是否生成成功, 错误信息)
        """
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return  {"code": 1000, "message": "请输入有效的11位手机号码"}

        try:
            # 生成4位随机数字验证码
            code = str(random.randint(1000, 9999))
            print(f"手机号{phone}生成的验证码是{encrypt_password(code)}({code})")
            code = encrypt_password(code)
            
            # 存储验证码到数据库
            success = await users_repository.verify_code(phone, code)
            
            if not success:
                return {"code": 1, "message": "验证码发送过于频繁，请1分钟后再试"}
                
            return {"code": 0, "message": "验证码生成成功"}
            
        except Exception as e:
            print(f"验证码生成失败: {str(e)}")
            return False, "验证码生成失败，请稍后重试"


    async def validate_username_data(self, username, password):
        """
        验证用户名和密码数据
        :param username: 用户名
        :param password: 密码
        :return: (bool, str) - (验证是否通过, 错误信息)
        """
        if not username or not password:
            return False, "用户名和密码不能为空"
        if not re.match(r'^[a-zA-Z0-9]{4,16}$', username):
            return False, "用户名必须是4-16位字母或数字的组合"
        if not re.match(r'^[a-zA-Z0-9]{6,16}$', password):
            return False, "密码必须是6-16位字母或数字的组合"
        return True, ""

    async def authenticate_user(self, username, password):
        """
        验证用户并生成token
        :param username: 用户名
        :param password: 密码
        :return: 包含token的字典,格式为 {"token": token_string}
        :raises HTTPException: 当用户名不存在、密码错误或token生成失败时抛出相应的HTTP 异常
        """
        # 验证数据
        is_valid, error_message = await self.validate_username_data(username, password)
        if not is_valid:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=error_message
            )

        # 验证用户
        user = await self.users_repository.get_user_by_username(username)
        if user is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户名不存在"
            )
        
        encrypted_password = encrypt_password(password)  # 加密输入的密码
        if encrypted_password != user["password"]:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="密码错误"
            )

        # 生成 token
        token_data = {
            "sub": username,  # sub 是 JWT 标准字段，表示主题（通常是用户ID）
            "user_id": user["id"],  # 添加用户ID到token数据中
            "exp": datetime.utcnow() + timedelta(minutes=self.__ACCESS_TOKEN_EXPIRE_MINUTES),
            "iat": datetime.utcnow(),  # 令牌创建时间
        }
        
        try:
            token = jwt.encode(token_data, self.__SECRET_KEY, algorithm=self.__ALGORITHM)
            return {"token": token}
        except Exception as e:
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="token生成失败"
            )


    async def validate_phone_data(self, phone, verify_code):
        """
        验证手机号和验证码数据
        :param phone: 手机号
        :param verify_code: 验证码
        :return: (bool, str) - (验证是否通过, 错误信息)
        """
        if not phone or not verify_code:
            return False, "手机号和验证码不能为空"
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return False, "请输入有效的11位手机号码"
        if not re.match(r'^\d{4}$', verify_code):
            return False, "验证码必须是4位数字"

        # 从数据库获取有效验证码
        valid_code = await users_repository.get_valid_code(phone)
        if not valid_code:
            return False, "验证码已过期或不存在"

        if decrypt_password(valid_code['code']) != verify_code:
            return False, "验证码错误"

        return True, ""

    async def authenticate_user_by_phone(self, phone, verify_code):
        """
        验证手机号并生成token
        :param phone: 手机号
        :param verify_code: 验证码
        :return: 包含token的字典,格式为 {"token": token_string}
        :raises HTTPException: 当手机号不存在、验证码错误或token生成失败时抛出相应的HTTP异常
        """
        # 验证数据
        is_valid, error_message = await self.validate_phone_data(phone, verify_code)
        if not is_valid:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=error_message
            )

        # 验证用户
        user = await self.users_repository.get_user_by_phone(phone)
        if user is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="手机号不存在"
            )

        # 生成 token
        token_data = {
            "sub": user["username"],  # sub 是 JWT 标准字段，表示主题（通常是用户ID）
            "user_id": user["id"],  # 添加用户ID到token数据中
            "exp": datetime.utcnow() + timedelta(minutes=self.__ACCESS_TOKEN_EXPIRE_MINUTES),
            "iat": datetime.utcnow(),  # 令牌创建时间
        }
        
        try:
            token = jwt.encode(token_data, self.__SECRET_KEY, algorithm=self.__ALGORITHM)
            return {"token": token}
        except Exception as e:
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="token生成失败"
            )

    async def verify_token(self, request):
        """
        验证token
        :param request: 请求对象
        :return: 用户id
        :raises HTTPException: 当token不存在、token格式错误或token过期时抛出相应的HTTP异常  
        """
        token = request.headers.get("token")
        if not token:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="未提供token"
            )
        
        # 如果token格式是 "Bearer <token>"，需要提取实际的token
        if token.startswith("Bearer "):
            token = token.split(" ")[1]

        try:
            # 解码并验证token
            payload = jwt.decode(token, self.__SECRET_KEY, algorithms=[self.__ALGORITHM])
            username = payload.get("sub")
            
            # 检查token是否过期
            exp = payload.get("exp")
            if datetime.utcnow() > datetime.fromtimestamp(exp):
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="token已过期"
                )

            # 验证用户是否存在
            user = await self.users_repository.get_user_by_username(username)
            if not user:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="用户不存在"
                )
                
            return user["id"]

        except jwt.ExpiredSignatureError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="token已过期"
            )
        except jwt.InvalidTokenError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无效的token"
            )
